package org.mx.notify.processor;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.mx.StringUtils;
import org.mx.service.server.websocket.WsConnectKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * WebSocket消息处理器抽象类定义
 * 
 * @author john.peng
 *
 */
public abstract class WsMessageProcessor {
	private static final Logger logger = LoggerFactory.getLogger(WsMessageProcessor.class);

	private String name;

	/**
	 * 构造函数
	 * 
	 * @param name 处理器名称
	 */
	public WsMessageProcessor(String name) {
		super();
		this.name = name;
	}

	/**
	 * 返回消息处理器名称
	 * 
	 * @return 名称
	 */
	public String getName() {
		return name;
	}

	/**
	 * 判断是否匹配本条消息
	 * 
	 * @param json JSON格式消息
	 * 
	 * @return 返回true表示匹配上
	 */
	public abstract boolean isMatched(JSONObject json);

	/**
	 * 判断是否匹配本条消息
	 * 
	 * @param xml XML格式消息
	 * 
	 * @return 返回true表示匹配上
	 */
	public abstract boolean isMatched(Document xml);

	/**
	 * 根据消息处理对应的业务逻辑
	 * 
	 * @param connectKey 连接关键字
	 * @param json       JSON格式消息
	 * @return 返回true表示消息被正确的处理
	 */
	public abstract boolean process(WsConnectKey connectKey, JSONObject json);

	/**
	 * 根据消息处理对应的业务逻辑
	 * 
	 * @param connectKey 连接关键字
	 * @param xml        XML格式消息
	 * @return 返回true表示消息被正确的处理
	 */
	public abstract boolean process(WsConnectKey connectKey, Document xml);

	/**
	 * 处理本条消息
	 * 
	 * @param connectKey     消息连接关键字
	 * @param messageContext 消息内容
	 * @return 处理结果状态
	 */
	public ProcessedState process(WsConnectKey connectKey, String messageContext) {
		try {
			if (StringUtils.isJSON(messageContext)) {
				JSONObject json = JSON.parseObject(messageContext);
				if (logger.isTraceEnabled()) {
					logger.trace(String.format("The message['%s'] is JSON.", messageContext));
				}
				if (!isMatched(json)) {
					return ProcessedState.SKIPED;
				}
				boolean result = process(connectKey, json);
				if (result) {
					if (logger.isTraceEnabled()) {
						logger.trace(String.format("The json message is processed success by %s.", name));
					}
					return ProcessedState.SUCCESS;
				} else {
					return ProcessedState.FAIL;
				}
			} else if (StringUtils.isXML(messageContext)) {
				Document xml = DocumentHelper.parseText(messageContext);
				if (logger.isTraceEnabled()) {
					logger.trace(String.format("The message['%s'] is XML.", messageContext));
				}
				if (!isMatched(xml)) {
					return ProcessedState.SKIPED;
				}
				boolean result = process(connectKey, xml);
				if (result) {
					if (logger.isTraceEnabled()) {
						logger.trace(String.format("The xml message is processed success by %s.", name));
					}
					return ProcessedState.SUCCESS;
				} else {
					return ProcessedState.FAIL;
				}
			} else {
				if (logger.isWarnEnabled()) {
					logger.warn(String.format("The message['%s'] has invalid format, only for JSON or XML.",
							messageContext));
				}
				return ProcessedState.SKIPED;
			}
		} catch (Exception ex) {
			if (logger.isErrorEnabled()) {
				logger.error(
						String.format("The message['%s'] from %s process fail.", connectKey.toString(), messageContext),
						ex);
			}
			return ProcessedState.FAIL;
		}
	}

	/**
	 * 消息处理器处理结果状态
	 * 
	 * @author john.peng
	 *
	 */
	public enum ProcessedState {
		/**
		 * 本处理器消息，且处理成功
		 */
		SUCCESS,
		/**
		 * 非本处理器消息，跳过
		 */
		SKIPED,
		/**
		 * 处理失败，发生了异常
		 */
		FAIL
	}
}
